use crate::rtmp::cache::errors::CacheError;
use crate::rtmp::chunk::errors::{PackError, UnpackError};
use crate::rtmp::handshake::errors::HandshakeError;
use crate::rtmp::messages::errors::MessageError;
use crate::rtmp::net_connection::errors::NetConnectionError;
use crate::rtmp::net_stream::errors::NetStreamError;
use crate::rtmp::protocol_control_messages::errors::ControlMessagesError;
use crate::rtmp::user_control_messages::errors::EventMessagesError;
use bytesio::bytes_errors::BytesWriteError;
use bytesio::bytesio_errors::BytesIOError;
use commonlib::errors::AuthError;
use failure::{Backtrace, Fail};
use std::fmt;
use streamhub::errors::StreamHubError;
use tokio::sync::oneshot::error::RecvError;
use xflv::amf0::Amf0WriteError;

#[derive(Debug, Fail)]
pub enum SessionErrorValue {
    // AMF0 编码写入错误
    #[fail(display = "amf0 write error: {}", _0)]
    Amf0WriteError(#[cause] Amf0WriteError),
    // 字节写入错误
    #[fail(display = "bytes write error: {}", _0)]
    BytesWriteError(#[cause] BytesWriteError),
    // 解包错误
    #[fail(display = "unpack error: {}", _0)]
    UnPackError(#[cause] UnpackError),

    // 消息处理错误
    #[fail(display = "messages error: {}", _0)]
    MessageError(#[cause] MessageError),
    // 控制消息错误
    #[fail(display = "control messages error: {}", _0)]
    ControlMessagesError(#[cause] ControlMessagesError),
    // 网络连接错误
    #[fail(display = "net connection error: {}", _0)]
    NetConnectionError(#[cause] NetConnectionError),
    // 网络流错误
    #[fail(display = "net stream error: {}", _0)]
    NetStreamError(#[cause] NetStreamError),

    // 事件消息错误
    #[fail(display = "event messages error: {}", _0)]
    EventMessagesError(#[cause] EventMessagesError),
    // 字节 IO 错误
    #[fail(display = "net io error: {}", _0)]
    BytesIOError(#[cause] BytesIOError),
    // 打包错误
    #[fail(display = "pack error: {}", _0)]
    PackError(#[cause] PackError),
    // 握手错误
    #[fail(display = "handshake error: {}", _0)]
    HandshakeError(#[cause] HandshakeError),
    // 缓存错误
    #[fail(display = "cache error name: {}", _0)]
    CacheError(#[cause] CacheError),
    // Tokio oneshot 接收错误
    #[fail(display = "tokio: oneshot receiver err: {}", _0)]
    RecvError(#[cause] RecvError),
    // StreamHub 通道错误
    #[fail(display = "streamhub channel err: {}", _0)]
    ChannelError(#[cause] StreamHubError),

    // AMF0 值数量不正确
    #[fail(display = "amf0 count not correct error")]
    Amf0ValueCountNotCorrectError,
    // AMF0 值类型不正确
    #[fail(display = "amf0 value type not correct error")]
    Amf0ValueTypeNotCorrectError,
    // StreamHub 事件发送错误
    #[fail(display = "stream hub event send error")]
    StreamHubEventSendError,
    // 无帧数据发送者错误
    #[fail(display = "none frame data sender error")]
    NoneFrameDataSenderError,
    // 无帧数据接收者错误
    #[fail(display = "none frame data receiver error")]
    NoneFrameDataReceiverError,
    // 发送帧数据错误
    #[fail(display = "send frame data error")]
    SendFrameDataError,
    // 订阅数量达到上限
    #[fail(display = "subscribe count limit is reached.")]
    SubscribeCountLimitReachError,

    // 无应用名称错误
    #[fail(display = "no app name error")]
    NoAppNameError,
    // 当前无媒体数据接收
    #[fail(display = "no media data can be received now.")]
    NoMediaDataReceivedError,

    // 会话结束
    #[fail(display = "session is finished.")]
    Finish,
    // 认证错误
    #[fail(display = "Auth err: {}", _0)]
    AuthError(#[cause] AuthError),
}

#[derive(Debug)]
pub struct SessionError {
    pub value: SessionErrorValue,
}

impl From<Amf0WriteError> for SessionError {
    fn from(error: Amf0WriteError) -> Self {
        SessionError {
            value: SessionErrorValue::Amf0WriteError(error),
        }
    }
}

impl From<BytesWriteError> for SessionError {
    fn from(error: BytesWriteError) -> Self {
        SessionError {
            value: SessionErrorValue::BytesWriteError(error),
        }
    }
}

impl From<UnpackError> for SessionError {
    fn from(error: UnpackError) -> Self {
        SessionError {
            value: SessionErrorValue::UnPackError(error),
        }
    }
}

impl From<MessageError> for SessionError {
    fn from(error: MessageError) -> Self {
        SessionError {
            value: SessionErrorValue::MessageError(error),
        }
    }
}

impl From<ControlMessagesError> for SessionError {
    fn from(error: ControlMessagesError) -> Self {
        SessionError {
            value: SessionErrorValue::ControlMessagesError(error),
        }
    }
}

impl From<NetConnectionError> for SessionError {
    fn from(error: NetConnectionError) -> Self {
        SessionError {
            value: SessionErrorValue::NetConnectionError(error),
        }
    }
}

impl From<NetStreamError> for SessionError {
    fn from(error: NetStreamError) -> Self {
        SessionError {
            value: SessionErrorValue::NetStreamError(error),
        }
    }
}

impl From<EventMessagesError> for SessionError {
    fn from(error: EventMessagesError) -> Self {
        SessionError {
            value: SessionErrorValue::EventMessagesError(error),
        }
    }
}

impl From<BytesIOError> for SessionError {
    fn from(error: BytesIOError) -> Self {
        SessionError {
            value: SessionErrorValue::BytesIOError(error),
        }
    }
}

impl From<PackError> for SessionError {
    fn from(error: PackError) -> Self {
        SessionError {
            value: SessionErrorValue::PackError(error),
        }
    }
}

impl From<HandshakeError> for SessionError {
    fn from(error: HandshakeError) -> Self {
        SessionError {
            value: SessionErrorValue::HandshakeError(error),
        }
    }
}

impl From<CacheError> for SessionError {
    fn from(error: CacheError) -> Self {
        SessionError {
            value: SessionErrorValue::CacheError(error),
        }
    }
}

impl From<RecvError> for SessionError {
    fn from(error: RecvError) -> Self {
        SessionError {
            value: SessionErrorValue::RecvError(error),
        }
    }
}

impl From<StreamHubError> for SessionError {
    fn from(error: StreamHubError) -> Self {
        SessionError {
            value: SessionErrorValue::ChannelError(error),
        }
    }
}
impl From<AuthError> for SessionError {
    fn from(error: AuthError) -> Self {
        SessionError {
            value: SessionErrorValue::AuthError(error),
        }
    }
}

impl fmt::Display for SessionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.value, f)
    }
}

impl Fail for SessionError {
    fn cause(&self) -> Option<&dyn Fail> {
        self.value.cause()
    }

    fn backtrace(&self) -> Option<&Backtrace> {
        self.value.backtrace()
    }
}
